/*
 * DOMHelper.java
 *
 * Created on April 23, 2007, 4:11 PM
 *
 *  Life Logger v1.0
    Copyright (C) 2007  Anand Kishore (anand@semanticvoid.com)
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

package com.semanticvoid.lifelogger.utils;

import com.semanticvoid.lifelogger.configuration.Constants;
import com.semanticvoid.lifelogger.entity.TaggedBrowseHistoryEntity;
import com.semanticvoid.lifelogger.entity.BrowseHistoryEntity;
import com.semanticvoid.lifelogger.entity.SearchHistoryEntity;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * This is a helper class for performing DOM functions.
 * @author anand kishore
 */
public class DOMHelper {
    
    /**
     * Check if the node represents a BrowseEntity (Google Web History item OR Google Search Clickthru item)
     * @param item the Node which may be BrowseEntity
     * @return true if yes
     * false otherwise
     */
    public static boolean isBrowseEntity(Node item) {
        NodeList childNodes = item.getChildNodes();
        
        for(int index=0; index<childNodes.getLength(); index++) {
            Node attribute = childNodes.item(index);
            String attribName = attribute.getNodeName();
            
            if(attribName.equalsIgnoreCase(Constants.GOOGLEHISTORY_ATTR_NAME_FOR_CATEGORY)) {
                String attribValue = attribute.getTextContent();
                if(attribValue.equalsIgnoreCase(Constants.NODE_NAME_FOR_BROWSE_RESULT) || attribValue.equalsIgnoreCase(Constants.NODE_NAME_FOR_WEB_RESULT)) {
                    return true;
                }
            }
        }
        
        return false;
    }
    
    /**
     * Check if the node represents a SearchEntity
     * @param item the node
     * @return true if yes
     * false otherwise
     */
    public static boolean isSearchEntity(Node item) {
        NodeList childNodes = item.getChildNodes();
        
        for(int index=0; index<childNodes.getLength(); index++) {
            Node attribute = childNodes.item(index);
            String attribName = attribute.getNodeName();
            
            if(attribName.equalsIgnoreCase(Constants.GOOGLEHISTORY_ATTR_NAME_FOR_CATEGORY)) {
                String attribValue = attribute.getTextContent();
                if(attribValue.equalsIgnoreCase(Constants.NODE_NAME_FOR_WEB_QUERY)) {
                    return true;
                }
            }
        }
        
        return false;
    }
    
    /**
     * Create a BrowseHistoryEntity from item
     * @param item the xml node
     * @return the BrowseHistoryEntity object
     */
    public static BrowseHistoryEntity formBrowseEntity(Node item) {
        String guid = null;
        String link = null;
        String title = null;
        Calendar date = null;
        String searchContext = null;
        short type = Constants.ITEM_TYPE_FOR_BROWSE;
        
        BrowseHistoryEntity bEntity = null;
        
        title = getTextOfChildNode(item, Constants.GOOGLEHISTORY_ATTR_NAME_FOR_TITLE);
        link = getTextOfChildNode(item, Constants.GOOGLEHISTORY_ATTR_NAME_FOR_LINK);
        guid = getTextOfChildNode(item, Constants.GOOGLEHISTORY_ATTR_NAME_FOR_GUID);
        
        date = Calendar.getInstance();
        date.setTimeInMillis(new Date().parse(getTextOfChildNode(item, Constants.GOOGLEHISTORY_ATTR_NAME_FOR_DATE)));
        date.setTimeZone(TimeZone.getTimeZone("GMT"));
        
        if(hasChildNode(item, Constants.GOOGLEHISTORY_ATTR_NAME_FOR_SEARCH_CONTEXT)) {
            searchContext = getTextOfChildNode(item, Constants.GOOGLEHISTORY_ATTR_NAME_FOR_SEARCH_CONTEXT);
            type = Constants.ITEM_TYPE_FOR_SEARCH_CLICKTHRU;
        }
        
        // @todo Parse the content
        bEntity = new BrowseHistoryEntity(guid, link, date, title, type, searchContext, "");
        
        return bEntity;
    }
    
    /**
     * Create a TaggedBrowseHistoryEntity object (Bookmark) from item
     * @param item the xml node
     * @return the TaggedBrowseHistoryEntity object
     */
    public static TaggedBrowseHistoryEntity formBookmarkEntity(Node item) {
        String guid = null;
        String link = null;
        String title = null;
        Calendar date = null;
        String[] tags = null;
        short type = Constants.ITEM_TYPE_FOR_BOOKMARK;
        
        
        TaggedBrowseHistoryEntity bEntity = null;
             
        title = getValueOfAttribute(item, Constants.DELICIOUS_ATTR_NAME_FOR_TITLE);
        link = getValueOfAttribute(item, Constants.DELICIOUS_ATTR_NAME_FOR_LINK);
        guid = getValueOfAttribute(item, Constants.DELICIOUS_ATTR_NAME_FOR_GUID);
        date = DateHelper.deliciousTimeToDate(getValueOfAttribute(item, Constants.DELICIOUS_ATTR_NAME_FOR_DATE));
        tags = getValueOfAttribute(item, Constants.DELICIOUS_ATTR_NAME_FOR_TAG).split(" ");
        
        // @todo Parse the content
        bEntity = new TaggedBrowseHistoryEntity(guid, link, date, title, tags, type, null, "");
        
        return bEntity;
    }
    
    /**
     * Create a TaggedBrowseHistoryEntity (GoogleReader Read Blog Post) entity from item
     * @param item the xml node
     * @return the TaggedBrowseHistoryEntity object
     */
    public static TaggedBrowseHistoryEntity formReadBlogEntity(Node item) {
        String guid = null;
        String link = null;
        String title = null;
        Calendar date = null;
        StringBuffer tagsBuff = new StringBuffer();
        String[] tags = null;
        String content = null;
        String author = null;
        short type = Constants.ITEM_TYPE_FOR_READ_BLOG;
        
        TaggedBrowseHistoryEntity bEntity = null;
        
        title = getTextOfChildNode(item, Constants.GOOGLEREADER_ATTR_NAME_FOR_TITLE);
        guid = getTextOfChildNode(item, Constants.GOOGLEREADER_ATTR_NAME_FOR_GUID);
        
        try {
            String timeInMillisSinceEpochStr = getValueOfAttribute(item, Constants.GOOGLEREADER_ATTR_NAME_FOR_TIME);
            long timeInMillsSinceEpoch = Long.valueOf(timeInMillisSinceEpochStr);
            date = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
            date.setTimeInMillis(timeInMillsSinceEpoch);
            //date = DateHelper.deliciousTimeToDate(getTextOfChildNode(item, Constants.GOOGLEREADER_ATTR_NAME_FOR_DATE));
        } catch(Exception e) {
            System.out.println("Could not form TaggedBrowseHistoryEntity  due to invalid timestamp: " + e);
            return null;
        }
        
        
        Node linkNode = getChildNode(item, Constants.GOOGLEREADER_ATTR_NAME_FOR_LINK);
        if(linkNode != null) {
            link = getValueOfAttribute(linkNode, Constants.GOOGLEREADER_ATTR_NAME_FOR_LINK_PROPERTY);
        } else {
            System.out.println("Could not form TaggedBrowseHistoryEntity as the link could not be extracted.");
            return null;
        }
        
        content = getTextOfChildNode(item, Constants.GOOGLEREADER_ATTR_NAME_FOR_CONTENT);
        if(content == null) {
            // @todo fetch the html content from the url
            content = "";
        }
        
        // SPECIAL HANDLING FOR TAGS
        // @todo better way for getting tags
        NodeList childNodes = item.getChildNodes();
        
        for(int i=0; i<childNodes.getLength(); i++) {
            Node attribute = childNodes.item(i);
            
            if(attribute.getNodeName().equalsIgnoreCase(Constants.GOOGLEREADER_ATTR_NAME_FOR_CATEGORY)) {
                String tagText = getValueOfAttribute(attribute, Constants.GOOGLEREADER_ATTR_NAME_FOR_CATEGORY_PROPERTY);
                
                // This check is needed as there is a 'category' node in the google reader xml which has the attribute
                // 'term' with the string that ends with 'state/com.google/read'. Hence we need to ignore this while
                // collecting the tags (categories)
                if(!tagText.matches("(.)*state/com.google/(.)*")) {
                    tagsBuff.append(getValueOfAttribute(attribute, Constants.GOOGLEREADER_ATTR_NAME_FOR_CATEGORY_PROPERTY) + " ");
                }
            } 
        }
        
        if(tagsBuff.toString().length() > 0) {
            // Set the tags
            tags = tagsBuff.toString().split(" ");
        }
                
        // @todo Parse the content
        bEntity = new TaggedBrowseHistoryEntity(guid, link, date, title, tags, type, author, content);
        
        return bEntity;
    }
    
    /**
     * Create a SearchHistoryEntity object (Google Search Query) from item
     * @param item the xml node
     * @return the SearchHistoryEntity object
     */
    public static SearchHistoryEntity formSearchEntity(Node item) {
        String guid = null;
        String link = null;
        String keywords = null;
        Calendar date = null;
        
        SearchHistoryEntity sEntity = null;
        
        keywords = getTextOfChildNode(item, Constants.GOOGLEHISTORY_ATTR_NAME_FOR_TITLE);
        link = getTextOfChildNode(item, Constants.GOOGLEHISTORY_ATTR_NAME_FOR_LINK);
        guid = getTextOfChildNode(item, Constants.GOOGLEHISTORY_ATTR_NAME_FOR_GUID);
        
        date = Calendar.getInstance();
        date.setTimeInMillis(new Date().parse(getTextOfChildNode(item, Constants.GOOGLEHISTORY_ATTR_NAME_FOR_DATE)));
        date.setTimeZone(TimeZone.getTimeZone("GMT"));
        
        sEntity = new SearchHistoryEntity(guid, link, date, keywords);
        
        return sEntity;
    }
    
    
    /**
     * Get value of an attribute for the give item
     * @param item the xml node
     * @param attributeIdentifier the name of the attribute
     * @return the value of the attribute
     */
    private static String getValueOfAttribute(Node item, String attributeIdentifier) {
        if(item == null || attributeIdentifier == null) {
            return null;
        }
        
        NamedNodeMap properties = item.getAttributes();
        
        for(int i=0; i<properties.getLength(); i++) {
            Node attr = properties.item(i);
            
            if(attr.getNodeName().equalsIgnoreCase(attributeIdentifier)) {
                return attr.getTextContent();
            }
        }
        
        return null;
    }

    /**
     * Get the text value of child node
     * @param node the parent xml node
     * @param childNodeIdentifier the node mane of the childnode
     * @return the text value of the childnode
     */
    private static String getTextOfChildNode(Node node, String childNodeIdentifier) {
        if(node == null || childNodeIdentifier == null) {
            return null;
        }
        
        NodeList childNodes = node.getChildNodes();
        
        for(int i=0; i<childNodes.getLength(); i++) {
            Node childNode = childNodes.item(i);
            
            if(childNode.getNodeName().equalsIgnoreCase(childNodeIdentifier)) {
                return childNode.getTextContent();
            }
        }
        
        return null;
    }

    /**
     * Check if the node has the specific child node
     * @param item the parent xml node
     * @param childNodeIdentifier the node name of the childnode
     * @return true if the parent node has the given childnode
     * false otherwise
     */
    private static boolean hasChildNode(Node item, String childNodeIdentifier) {
        if(item == null || childNodeIdentifier == null) {
            return false;
        }
        
        NodeList childNodes = item.getChildNodes();
        
        for(int i=0; i<childNodes.getLength(); i++) {
            Node childNode = childNodes.item(i);
            
            if(childNode.getNodeName().equalsIgnoreCase(childNodeIdentifier)) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * Get the xml node representing the child node
     * @param item the parent xml node
     * @param childNodeIdentifier the nodename of the childnode
     * @return the Node object representing the childnode
     */
    private static Node getChildNode(Node item, String childNodeIdentifier) {
        if(item == null || childNodeIdentifier == null) {
            return null;
        }
        
        NodeList childNodes = item.getChildNodes();
        
        for(int i=0; i<childNodes.getLength(); i++) {
            Node childNode = childNodes.item(i);
            
            if(childNode.getNodeName().equalsIgnoreCase(childNodeIdentifier)) {
                return childNode;
            }
        }
        
        return null;
    }
}
